package parser;

import error.ErrorType;

import java.util.ArrayList;
import java.util.List;

import error.Error;
import node.*;
import symbol.ArraySymbol;
import symbol.BasicSymbol;
import symbol.ScopeStack;
import symbol.Symbol;
import symbol.SymbolKind;
import symbol.SymbolType;

public class SymbolBuilder {
    private static SymbolBuilder instance;
    private ScopeStack scopeStack = ScopeStack.getInstance();
    private IrBuilder irBuilder = IrBuilder.getInstance();
    private Error error = Error.getInstance();

    private SymbolBuilder() {
    }

    public static SymbolBuilder getInstance() {
        if (instance == null) {
            instance = new SymbolBuilder();
        }
        return instance;
    }

    public void buildConst(BTypeNode bTypeNode, ConstDefNode constDefNode) {
        if (!constDefNode.isArray()) {
            String identNode = constDefNode.getIdentNode();
            // 将int或char类型转换为SymbolType
            SymbolType symbolType = bTypeNode.getType().equals("int")
                    ? SymbolType.INT
                    : SymbolType.CHAR;

            if (scopeStack.getSymbol(identNode) != null) {
                // B类错误：重复定义
                error.addError(constDefNode.getLineno(), ErrorType.B);
            } else {
                // 常量一定有初值
                scopeStack.addSymbol(identNode, symbolType, SymbolKind.CONSTANT,
                        constDefNode.getConstInitValNode().calculate());
            }
        } else {
            String identNode = constDefNode.getIdentNode();
            ConstExpNode constExpNode = constDefNode.getConstExpNode();
            SymbolType symbolType = bTypeNode.getType().equals("int")
                    ? SymbolType.INT
                    : SymbolType.CHAR;
            if (scopeStack.getSymbol(identNode) != null) {
                // B类错误：重复定义
                error.addError(constDefNode.getLineno(), ErrorType.B);
            } else {
                scopeStack.addSymbol(identNode, symbolType, SymbolKind.CONSTANT,
                        constExpNode.calculate(), constDefNode.getConstInitValNode().calculateArray());

            }
        }
    }

    public void buildVar(BTypeNode bTypeNode, VarDefNode varDefNode) {
        if (!varDefNode.isArray()) {
            String identNode = varDefNode.getIdentNode();
            // 将int或char类型转换为SymbolType
            SymbolType symbolType = bTypeNode.getType().equals("int")
                    ? SymbolType.INT
                    : SymbolType.CHAR;
            if (scopeStack.getSymbol(identNode) != null) {
                // B类错误：重复定义
                error.addError(varDefNode.getLineno(), ErrorType.B);
            } else {
                // 变量可能没有初值
                if (irBuilder.inGlobal == true && varDefNode.getInitValNode() != null) {
                    scopeStack.addSymbol(identNode, symbolType, SymbolKind.VARIABLE,
                            varDefNode.getInitValNode().calculate());
                } else if (irBuilder.inGlobal == true) {
                    scopeStack.addSymbol(identNode, symbolType, SymbolKind.VARIABLE, 0);
                } else {
                    scopeStack.addSymbol(identNode, symbolType, SymbolKind.VARIABLE);
                }
            }
        } else {
            String identNode = varDefNode.getIdentNode();
            ConstExpNode constExpNode = varDefNode.getConstExpNode();
            SymbolType symbolType = bTypeNode.getType().equals("int")
                    ? SymbolType.INT
                    : SymbolType.CHAR;
            if (scopeStack.getSymbol(identNode) != null) {
                // B类错误：重复定义
                error.addError(varDefNode.getLineno(), ErrorType.B);
            } else {
                if (irBuilder.inGlobal == true && varDefNode.getInitValNode() != null) {
                    scopeStack.addSymbol(identNode, symbolType, SymbolKind.VARIABLE, constExpNode.calculate(),
                            varDefNode.getInitValNode().calculateArray());
                } else if (irBuilder.inGlobal == true) {
                    // List<Integer> valueList 初始化为全0
                    scopeStack.addSymbol(identNode, symbolType, SymbolKind.VARIABLE, constExpNode.calculate(), null);
                } else {
                    scopeStack.addSymbol(identNode, symbolType, SymbolKind.VARIABLE, constExpNode.calculate(), null);
                }

            }
        }
    }

    public void buildPara(FuncFParamsNode funcFParamsNode) {
        List<FuncFParamNode> funcFParamNodes = funcFParamsNode.getFuncFParamNodes();
        for (FuncFParamNode funcFParamNode : funcFParamNodes) {
            String ident = funcFParamNode.getIdentNode();
            SymbolType symbolType = funcFParamNode.getbTypeNode().getType().equals("int") ? SymbolType.INT
                    : SymbolType.CHAR;
            if (scopeStack.getSymbol(funcFParamNode.getIdentNode()) != null) {
                // B类错误：重复定义
                error.addError(funcFParamNode.getLineno(), ErrorType.B);
                return;
            }
            if (funcFParamNode.isArray()) {
                scopeStack.addSymbol(ident, symbolType, SymbolKind.VARIABLE, -1, new ArrayList<>());
            } else {
                scopeStack.addSymbol(ident, symbolType, SymbolKind.VARIABLE);
            }
        }
    }

    public void buildFunc(FuncTypeNode funcTypeNode, String identNode, FuncFParamsNode funcFParamsNode, int lineno) {
        // 确定函数的返回值类型 int or void or char
        SymbolType symbolType;
        if (funcTypeNode.getType().equals("int")) {
            symbolType = SymbolType.INT;
        } else if (funcTypeNode.getType().equals("char")) {
            symbolType = SymbolType.CHAR;
        } else {
            symbolType = SymbolType.VOID;
        }

        if (funcFParamsNode == null) {
            if (scopeStack.getSymbol(identNode) != null) {
                // B类错误：重复定义
                error.addError(lineno, ErrorType.B);
            } else {
                scopeStack.addSymbol(identNode, symbolType, 0, null);
            }
            return;
        }

        int paramNum = funcFParamsNode.getFuncFParamNodes().size();

        List<Symbol> paramList = new ArrayList<>();

        for (FuncFParamNode funcFParamNode : funcFParamsNode.getFuncFParamNodes()) {
            if (funcFParamNode.getbTypeNode().getType().equals("int")) {
                if (funcFParamNode.isArray()) {
                    paramList.add(
                            new ArraySymbol(funcFParamNode.getIdentNode(), SymbolType.INT, -1, SymbolKind.VARIABLE, -1,
                                    -1));
                } else {
                    paramList.add(new BasicSymbol(funcFParamNode.getIdentNode(), SymbolType.INT, SymbolKind.VARIABLE,
                            -1, -1));
                }
            } else if (funcFParamNode.getbTypeNode().getType().equals("char")) {
                if (funcFParamNode.isArray()) {
                    paramList.add(
                            new ArraySymbol(funcFParamNode.getIdentNode(), SymbolType.CHAR, -1, SymbolKind.VARIABLE, -1,
                                    -1));
                } else {
                    paramList.add(new BasicSymbol(funcFParamNode.getIdentNode(), SymbolType.CHAR, SymbolKind.VARIABLE,
                            -1, -1));
                }
            }
        }

        if (scopeStack.getSymbol(identNode) != null) {
            // B类错误：重复定义
            error.addError(lineno, ErrorType.B);
        } else {
            scopeStack.addSymbol(identNode, symbolType, paramNum, paramList);
        }
    }
}
